/**
 * www.easyplatform.cn ©2016
 */
package cn.easyplatform.studio.web.editors.entity;

import cn.easyplatform.entities.beans.table.TableBean;
import cn.easyplatform.entities.beans.table.TableField;
import cn.easyplatform.entities.beans.table.TableFk;
import cn.easyplatform.entities.beans.table.TableIndex;
import cn.easyplatform.lang.Lang;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.studio.StudioApp;
import cn.easyplatform.studio.cmd.entity.GetEntityCmd;
import cn.easyplatform.studio.context.Contexts;
import cn.easyplatform.studio.utils.StringUtil;
import cn.easyplatform.studio.utils.StudioUtil;
import cn.easyplatform.studio.utils.WebUtils;
import cn.easyplatform.studio.vos.TableCodeLabelVo;
import cn.easyplatform.studio.web.editors.AbstractEntityEditor;
import cn.easyplatform.studio.web.editors.BandboxCallback;
import cn.easyplatform.studio.web.editors.Editor;
import cn.easyplatform.studio.web.editors.EditorCallback;
import cn.easyplatform.studio.web.layout.WorkbenchController;
import cn.easyplatform.studio.web.views.impl.AbstractView;
import cn.easyplatform.type.EntityType;
import cn.easyplatform.type.FieldType;
import cn.easyplatform.web.ext.cmez.CMeditor;
import org.apache.commons.lang3.StringUtils;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.Page;
import org.zkoss.zk.ui.UiException;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.OpenEvent;
import org.zkoss.zkmax.zul.Chosenbox;
import org.zkoss.zul.*;

import java.util.*;

/**
 * @author <a href="mailto:shiny_vc@163.com">陈云亮</a> <br/>
 * @since 2.0.0 <br/>
 */
public class TableEntityEditor extends AbstractEntityEditor<TableBean> {

    private Tabbox tabbox;

    private Checkbox autokey;

    private Checkbox byDb;

    private Checkbox cachable;

    private Textbox entityName;

    private Textbox entityDesp;

    private Bandbox entityDb;

    private Listbox fields;

    private Grid indexes;

    private Grid foreignkeys;

    private CMeditor views;

    /**
     * @param workbench
     * @param entity
     * @param code
     */
    public TableEntityEditor(WorkbenchController workbench, TableBean entity,
                             char code) {
        super(workbench, entity, code);
    }

    @Override
    public void create(Object... args) {
        super.create(args);
        Tabpanel tabpanel = new Tabpanel();
        Idspace is = new Idspace();
        is.setHflex("1");
        is.setVflex("1");
        is.setParent(tabpanel);
        Executions.createComponents("~./include/editor/entity/table.zul", is,
                null);
        String theme = Contexts.getUser().getEditorTheme();
        for (Component comp : is.getFellows()) {
            if (comp.getId().equals("entityTable_switchbox_autokey")) {
                autokey = (Checkbox) comp;
                autokey.setChecked(entity.isAutoKey());
                comp.addEventListener(Events.ON_CHECK, this);
            }
            if (comp.getId().equals("entityTable_switchbox_byDb")) {
                byDb = (Checkbox) comp;
                byDb.setChecked(entity.isByDb());
                if (entity.isAutoKey()){
                    byDb.setVisible(true);
                    byDb.getPreviousSibling().setVisible(true);
                }else {
                    byDb.setVisible(false);
                    byDb.getPreviousSibling().setVisible(false);
                }
                comp.addEventListener(Events.ON_CHECK, this);
            }
            if (comp.getId().equals("entityTable_switchbox_cachable")) {
                cachable = (Checkbox) comp;
                cachable.setChecked(entity.isCacheable());
                comp.addEventListener(Events.ON_CHECK, this);
            } else if (comp.getId().equals("entityTable_textbox_name")) {
                entityName = (Textbox) comp;
                comp.addEventListener(Events.ON_CHANGE, this);
                entityName.setValue(entity.getName());
            } else if (comp.getId().equals("entityTable_textbox_desp")) {
                entityDesp = (Textbox) comp;
                comp.addEventListener(Events.ON_CHANGE, this);
                entityDesp.setValue(entity.getDescription());
            } else if (comp.getId().equals("entityTable_bandbox_db")) {
                entityDb = (Bandbox) comp;
                comp.addEventListener(Events.ON_CHANGE, this);
                comp.addEventListener(Events.ON_OPEN, this);
                entityDb.setValue(entity.getSubType());
            } else if (comp.getId().equals("entityTable_listbox_fields")) {
                fields = (Listbox) comp;
                fields.getPagingChild().setMold("os");
            } else if (comp.getId().equals("entityTable_a_addField")) {
                comp.addEventListener(Events.ON_CLICK, this);
            } else if (comp.getId().equals("entityTable_a_insertField")) {
                comp.addEventListener(Events.ON_CLICK, this);
            } else if (comp.getId().equals("entityTable_a_deleteField")) {
                comp.addEventListener(Events.ON_CLICK, this);
            } else if (comp.getId().equals("entityTable_a_primaryKey")) {
                comp.addEventListener(Events.ON_CLICK, this);
            } else if (comp.getId().equals("entityTable_a_moveUp")) {
                comp.addEventListener(Events.ON_CLICK, this);
            } else if (comp.getId().equals("entityTable_a_moveDown")) {
                comp.addEventListener(Events.ON_CLICK, this);
            } else if (comp.getId().equals("entityTable_a_auto")) {
                comp.addEventListener(Events.ON_CLICK, this);
            }  else if (comp.getId().equals("entityTable_cmeditor_views")) {
                if(this.isDirty()) {
                    this.save();
                }
                views = (CMeditor) comp;
                views.setTheme(theme);
                views.setValue(entity.getView());
                views.addEventListener(Events.ON_CHANGING, this);
            } else if (comp.getId().equals("entityTable_grid_foreignkeys")) {
                foreignkeys = (Grid) comp;
            } else if (comp.getId().equals("entityTable_grid_indexes")) {
                indexes = (Grid) comp;
            } else if (comp.getId().equals("addTrigger"))
                comp.addEventListener(Events.ON_CLICK, this);
            else if (comp.getId().equals("entityTable_column_foreignkeys_addFk"))
                comp.addEventListener(Events.ON_CLICK, this);
            else if (comp.getId().equals("entityTable_column_indexes_addIndex"))
                comp.addEventListener(Events.ON_CLICK, this);
            else if (comp.getId().equals("entityTable_cmeditor_source")) {
                source = (CMeditor) comp;
                source.setTheme(theme);
            } else if (comp.getId().equals("entityTable_tabbox_main")) {
                tabbox = (Tabbox) comp;
                tabbox.addEventListener(Events.ON_SELECT, this);
            }
        }
        if (entity.getFields() != null) {
            for (TableField field : entity.getFields())
                createField(field, -1);
        }
        if (entity.getIndexes() != null) {
            for (TableIndex index : entity.getIndexes())
                createIndex(index);
        }
        if (entity.getForeignKeys() != null) {
            for (TableFk fk : entity.getForeignKeys())
                createForeignKey(fk);
        }
        workbench.addEditor(tab, tabpanel);
    }

    @Override
    protected boolean validate() {
        if (Strings.isBlank(entity.getName())) {
            WebUtils.notEmpty(Labels.getLabel("entity.name"));
            return false;
        }
        entity.setView((String) views.getValue());
        if (Strings.isBlank(entity.getView())) {
            //主键为空
            if (entity.getKey() == null || entity.getKey().isEmpty()) {
                WebUtils.showError(Labels.getLabel("entity.table.key.set"));
                return false;
            }
            //字段列表为空
            if (entity.getFields() == null || entity.getFields().isEmpty()) {
                WebUtils.showError(Labels.getLabel("entity.table.field.set"));
                return false;
            }
            //自增长判断
            if (entity.isAutoKey()) {
                if (entity.getKey().size() == 1) {
                    String key = entity.getKey().get(0);
                    for (TableField field : entity.getFields()) {
                        if (field.getName().equals(key)) {
                            if (field.getType() != FieldType.INT
                                    && field.getType() != FieldType.LONG
                                    && field.getType() != FieldType.NUMERIC) {
                                WebUtils.showError(Labels
                                        .getLabel("entity.table.auto.key.error"));
                                return false;
                            }
                            break;
                        }
                    }
                } else {
                    WebUtils.showError(Labels
                            .getLabel("entity.table.auto.key.error"));
                    return false;
                }
            }
            //字段判断
            List<String> fieldNameList = new ArrayList<>();
            for (TableField field : entity.getFields()) {
                fieldNameList.add(field.getName());
                if (Strings.isBlank(field.getName())) {
                    WebUtils.showError(Labels
                            .getLabel("entity.table.field.name.not.empty"));
                    return false;
                } else if(field.getName().matches("^[a-zA-Z]\\S*$") == false){
                    WebUtils.showError(Labels
                            .getLabel("entity.table.field.name.is.char"));
                    return false;
                }
            }
            //重复字段名称
            Set<String> fieldNameSet = new HashSet<>(fieldNameList);
            boolean  result= fieldNameSet.size() == fieldNameList.size() ? true : false;
            if (result == false) {
                WebUtils.showError(Labels
                        .getLabel("entity.table.field.name.not.double"));
                return false;
            }
            //索引判断
            if (entity.getIndexes() != null) {
                if (entity.getIndexes().isEmpty()) {
                    entity.setIndexes(null);
                } else {
                    for (TableIndex index : entity.getIndexes()) {
                        if (Strings.isBlank(index.getName())) {
                            WebUtils.notEmpty(Labels
                                    .getLabel("entity.table.index.name"));
                            return false;
                        }
                        if (Strings.isBlank(index.getFields())) {
                            WebUtils.notEmpty(Labels
                                    .getLabel("entity.table.index.field"));
                            return false;
                        }
                    }
                }
            }
            //外键判断
            if (entity.getForeignKeys() != null) {
                if (entity.getForeignKeys().isEmpty()) {
                    entity.setForeignKeys(null);
                } else {
                    for (TableFk fk : entity.getForeignKeys()) {
                        if (Strings.isBlank(fk.getName())) {
                            WebUtils.notEmpty(Labels
                                    .getLabel("entity.table.fk.name"));
                            return false;
                        }
                        if (Strings.isBlank(fk.getSourceFields())) {
                            WebUtils.notEmpty(Labels
                                    .getLabel("entity.table.fk.field"));
                            return false;
                        }
                        if (Strings.isBlank(fk.getReferences())) {
                            WebUtils.notEmpty(Labels
                                    .getLabel("entity.table.fk.table"));
                            return false;
                        }
                        if (Strings.isBlank(fk.getToFields())) {
                            WebUtils.notEmpty(Labels.getLabel("entity.table.fk.to"));
                            return false;
                        }
                        if (StringUtils.countMatches(fk.getSourceFields(), ",") != StringUtils
                                .countMatches(fk.getToFields(), ",")) {// 栏位数不匹配
                            WebUtils.showError(Labels
                                    .getLabel("entity.table.fk.field.match"));
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }

    /**
     * 不实现
     */
    @Override
    protected void refreshSource() {
        if (tabbox.getSelectedIndex() == 4)
            super.refreshSource();
    }

    /**
     * 创建索引
     *
     * @param index
     */
    private void createIndex(TableIndex index) {
        Row row = new Row();
        row.setValue(index);
        // name
        Textbox name = new Textbox();
        name.setHflex("1");
        name.setValue(index.getName());
        name.setParent(row);
        // unique
        Checkbox unique = new Checkbox();
        unique.setChecked(index.isUnique());
        unique.setParent(row);
        // fields
        Chosenbox fields = new Chosenbox();
        fields.setHflex("1");
        fields.setCreatable(false);
        if (entity.getFields() != null) {
            ListModelList<String> model = new ListModelList<String>(entity
                    .getFields().size());
            for (TableField field : entity.getFields())
                model.add(field.getName());
            fields.setModel(model);
            if (!Strings.isBlank(index.getFields())) {
                try {//web bug
                    fields.setSelectedObjects(Arrays.asList(index.getFields()
                            .split(",")));
                } catch (Exception ex) {
                }
            }
        }
        fields.setParent(row);
        // button
        A btn = new A();
        btn.setTooltiptext(Labels.getLabel("button.delete"));
        btn.setIconSclass("z-icon-times");
        btn.setParent(row);

        row.setParent(indexes.getRows());
        new IndexObject(name, fields, unique, btn);
    }

    /**
     * 创建外键
     *
     * @param fk
     */
    private void createForeignKey(TableFk fk) {
        Row row = new Row();
        row.setValue(fk);
        // name
        Textbox name = new Textbox();
        name.setHflex("1");
        name.setValue(fk.getName());
        name.setParent(row);
        // sourceFields
        Chosenbox sourceFields = new Chosenbox();
        sourceFields.setHflex("1");
        sourceFields.setCreatable(false);
        if (entity.getFields() != null) {
            ListModelList<String> model = new ListModelList<String>(entity
                    .getFields().size());
            for (TableField field : entity.getFields())
                model.add(field.getName());
            sourceFields.setModel(model);
            if (!Strings.isBlank(fk.getSourceFields()))
                sourceFields.setSelectedObjects(Arrays.asList(fk
                        .getSourceFields().split(",")));
        }
        sourceFields.setParent(row);
        // table
        Bandbox table = new Bandbox();
        table.setHflex("1");
        table.setValue(fk.getReferences());
        table.setParent(row);
        // toFields
        Chosenbox toFields = new Chosenbox();
        toFields.setHflex("1");
        toFields.setCreatable(false);
        if (!Strings.isBlank(fk.getReferences())) {
            TableBean e = (TableBean) StudioApp.execute(null, new GetEntityCmd(
                    fk.getReferences()));
            if (e != null) {
                ListModelList<String> model = new ListModelList<String>(e
                        .getFields().size());
                for (TableField field : e.getFields())
                    model.add(field.getName());
                toFields.setModel(model);
                if (!Strings.isBlank(fk.getToFields()))
                    toFields.setSelectedObjects(Arrays.asList(fk.getToFields()
                            .split(",")));
            }
        }
        toFields.setParent(row);
        // action
        Textbox action = new Textbox();
        action.setHflex("1");
        action.setValue(fk.getAction());
        action.setParent(row);
        // button
        A btn = new A();
        btn.setTooltiptext(Labels.getLabel("button.delete"));
        btn.setIconSclass("z-icon-times");
        btn.setParent(row);

        row.setParent(foreignkeys.getRows());

        new foreignKeyObject(name, sourceFields, table, toFields, action, btn);
    }

    /**
     * 生成栏位
     *
     * @param field
     */
    private Listitem createField(TableField field, int pos) {
        Listitem row = new Listitem();
        row.setValue(field);
        row.appendChild(new Listcell());
        // name
        Listcell cell = new Listcell();
        Textbox name = new Textbox(field.getName());
        name.setHflex("1");
        name.setParent(cell);
        cell.setParent(row);
        // type
        cell = new Listcell();
        Combobox type = WebUtils.createFieldTypeBox();
        type.setValue(field.getType().name());
        type.setHflex("1");
        type.setParent(cell);
        cell.setParent(row);
        // length
        cell = new Listcell();
        Intbox length = new Intbox(field.getLength());
        length.setConstraint("no negative,no empty");
        length.setHflex("1");
        length.setParent(cell);
        cell.setParent(row);
        // decimal
        cell = new Listcell();
        Intbox decimal = new Intbox(field.getDecimal());
        decimal.setConstraint("no negative,no empty");
        decimal.setHflex("1");
        decimal.setParent(cell);
        cell.setParent(row);
        // not null
        cell = new Listcell();
        Checkbox notnull = new Checkbox();
        Boolean isNotNull = false;
        if (field.isNotNull() != null) {
            isNotNull = field.isNotNull();
        }
        notnull.setChecked(isNotNull);
        notnull.setParent(cell);
        cell.setParent(row);
        // desp
        cell = new Listcell();
        Textbox desp = new Textbox(field.getDescription());
        desp.setHflex("1");
        desp.setParent(cell);
        cell.setParent(row);
        // value
        cell = new Listcell();
        Textbox value = new Textbox(field.getDefaultValue());
        value.setHflex("1");
        value.setParent(cell);
        cell.setParent(row);
        // acc
        cell = new Listcell();
        Textbox acc = new Textbox(field.getAcc());
        acc.setHflex("1");
        acc.setParent(cell);
        cell.setParent(row);
        // option type
        cell = new Listcell();
        Combobox optionTypeCombobox = WebUtils.createOptionTypeBox();
        Integer optionType = 0;
        if (field.getOptionType() != null) {
            optionType = field.getOptionType();
        }
        int types = getTableOptionType(optionType, field.getOptionValue());
        String values = Labels.getLabel("entity.table.none");
        if (types == 1) {
            values = Labels.getLabel("entity.table.dictionary");
        } else if (types == 2) {
            values = Labels.getLabel("entity.table.table");
        }
        optionTypeCombobox.setValue(values);
        optionTypeCombobox.setSelectedIndex(types);
        optionTypeCombobox.setHflex("1");
        optionTypeCombobox.setParent(cell);
        cell.setParent(row);
        // option Value
        cell = new Listcell();
        Bandbox valueBandbox = new Bandbox();
        valueBandbox.setHflex("1");
        valueBandbox.setReadonly(true);
        valueBandbox.setParent(cell);
        valueBandbox.setValue(field.getOptionValue());
        cell.setParent(row);
        // main key
        Listcell key = new Listcell();
        if (entity.getKey() != null
                && entity.getKey().contains(field.getName())) {
            key.setIconSclass("z-icon-key");
            key.setLabel((entity.getKey().indexOf(field.getName()) + 1) + "");
        }
        key.setSclass("epeditor-key");
        key.setParent(row);
        if (pos >= 0) {
            fields.getItems().add(pos, row);
        } else
            row.setParent(fields);
        new FieldObject(name, type, length, decimal, value, desp, notnull, key,
                acc, optionTypeCombobox, valueBandbox);
        return row;
    }

    private int getTableOptionType(int type, String value) {
        if (type == 1) {
            if (Strings.isBlank(value) == false) {
                List<String> stringList = Arrays.asList(value.split(","));
                if (stringList.size() > 1) {
                    return 2;
                } else {
                    return 1;
                }
            }
        }
        return 0;
    }

    @Override
    protected void dispatch(Event evt) {
        if (evt.getName().equals(Events.ON_CHANGE)
                || evt.getName().equals(Events.ON_CHECK)
                || evt.getName().equals(Events.ON_CHANGING)) {
            Component c = evt.getTarget();
            if (c == autokey) {
                if (autokey.isChecked()) {
                    if (entity.getKey() != null && entity.getKey().size() == 1
                            && entity.getFields() != null
                            && !entity.getFields().isEmpty()) {
                        String key = entity.getKey().get(0);
                        for (TableField field : entity.getFields()) {
                            if (field.getName().equals(key)) {
                                if (field.getType() != FieldType.INT
                                        && field.getType() != FieldType.LONG
                                        && field.getType() != FieldType.NUMERIC) {
                                    WebUtils.showError(Labels
                                            .getLabel("entity.table.auto.key.error"));
                                    autokey.setChecked(false);
                                    return;
                                }
                                break;
                            }
                        }
                    } else {
                        WebUtils.showError(Labels
                                .getLabel("entity.table.auto.key.error"));
                        autokey.setChecked(false);
                        return;
                    }
                }
                entity.setAutoKey(autokey.isChecked());
                if (autokey.isChecked()){
                    byDb.setVisible(true);
                    byDb.getPreviousSibling().setVisible(true);
                }else {
                    byDb.setVisible(false);
                    byDb.getPreviousSibling().setVisible(false);
                    byDb.setChecked(false);
                    entity.setByDb(false);
                }
            } else if(c == byDb){
                entity.setByDb(byDb.isChecked());
            } else if (c == entityName)
                entity.setName(entityName.getValue());
            else if (c == entityDesp)
                entity.setDescription(entityDesp.getValue());
            else if (c == entityDb)
                entity.setSubType(entityDb.getValue());
            else if (c == views)
                entity.setView((String) views.getValue());
            else if (c == cachable)
                entity.setCacheable(cachable.isChecked());
            setDirty();
        } else if (evt.getName().equals(Events.ON_CLICK)) {
            String id = evt.getTarget().getId();
            if ("entityTable_a_addField".equals(id)) {
                TableField field = new TableField();
                field.setNotNull(false);
                field.setType(FieldType.VARCHAR);
                if (entity.getFields() == null)
                    entity.setFields(new ArrayList<TableField>());
                entity.getFields().add(field);
                Listitem row = createField(field, -1);
                setDirty();
                fields.setActivePage(row);
            } else if ("entityTable_a_insertField".equals(id)) {
                int pos = fields.getSelectedIndex();
                TableField field = new TableField();
                field.setNotNull(false);
                field.setType(FieldType.VARCHAR);
                if (entity.getFields() == null)
                    entity.setFields(new ArrayList<TableField>());
                if (pos >= 0) {
                    pos++;
                    entity.getFields().add(pos, field);
                } else
                    entity.getFields().add(field);
                createField(field, pos);
                setDirty();
            } else if ("entityTable_a_deleteField".equals(id)) {
                if (fields.getSelectedItem() != null)
                    WebUtils.showConfirm(Labels.getLabel("button.delete"), this);
            } else if ("entityTable_a_primaryKey".equals(id)) {
                if (fields.getSelectedItem() != null) {
                    TableField field = fields.getSelectedItem().getValue();
                    if (Strings.isBlank(field.getName())) {
                        WebUtils.showError(Labels
                                .getLabel("entity.table.auto.key.error"));
                        return;
                    }
                    setPrimaryKey(field.getName(), (Listcell) fields
                            .getSelectedItem().getLastChild());
                }
            } else if ("entityTable_a_moveUp".equals(id)) {
                if (fields.getSelectedItem() != null)
                    moveField(false);
            } else if ("entityTable_a_moveDown".equals(id)) {
                if (fields.getSelectedItem() != null)
                    moveField(true);
            } else if ("entityTable_a_auto".equals(id)) {
                Map arg = new HashMap();
                arg.put("comp", this);
                Component newComp = Executions.createComponents("~./include/wizards/tableTemp.zul", null,
                        arg);
            } else if ("entityTable_column_indexes_addIndex".equals(id)) {
                if (entity.getIndexes() == null)
                    entity.setIndexes(new ArrayList<TableIndex>());
                TableIndex index = new TableIndex();
                entity.getIndexes().add(index);
                createIndex(index);
                setDirty();
            } else if ("entityTable_column_foreignkeys_addFk".equals(id)) {
                if (entity.getForeignKeys() == null)
                    entity.setForeignKeys(new ArrayList<TableFk>());
                TableFk fk = new TableFk();
                entity.getForeignKeys().add(fk);
                createForeignKey(fk);
                setDirty();
            } else if ("addTrigger".equals(id)) {

            }
        } else if (evt.getName().equals(Events.ON_OK)) {// 删除栏位
            TableField field = fields.getSelectedItem().getValue();
            entity.getFields().remove(field);
            if (entity.getKey() != null) {
                Iterator<String> itr = entity.getKey().iterator();
                while (itr.hasNext()) {
                    String name = itr.next();
                    if (name.equals(field.getName())) {
                        if (entity.isAutoKey()) {
                            entity.setAutoKey(false);
                            autokey.setChecked(false);
                        }
                        itr.remove();
                        break;
                    }
                }
            }
            fields.getSelectedItem().detach();
            setDirty();
        } else if (evt.getName().equals(Events.ON_SELECT)
                && evt.getTarget() instanceof Tab) {
            refreshSource();
        } else if (evt.getTarget() == entityDb) {
            AbstractView.createDatasourceView(
                    new BandboxCallback(entityDb, Labels
                            .getLabel("entity.table.db")), evt.getTarget()).doOverlapped();
        }
    }

    /**
     * 移动栏位
     *
     * @param down
     */
    private void moveField(boolean down) {
        Listitem item = fields.getSelectedItem();
        TableField field = item.getValue();
        int pos = fields.getSelectedIndex();
        if (down)
            pos++;
        else
            pos--;
        if (pos < 0)
            pos = 0;
        else if (pos >= fields.getItemCount())
            pos = fields.getItemCount() - 1;
        item.detach();
        fields.getItems().add(pos, item);
        entity.getFields().remove(field);
        entity.getFields().add(pos, field);
        setDirty();
    }

    /**
     * 设置主键
     *
     * @param name
     * @param cell
     */
    private void setPrimaryKey(String name, Listcell cell) {
        if (entity.getKey() != null) {
            if (cell.getIconSclass() != null) {
                Iterator<String> itr = entity.getKey().iterator();
                while (itr.hasNext()) {
                    if (itr.next().equalsIgnoreCase(name)) {
                        itr.remove();
                        break;
                    }
                }
            } else {
                entity.getKey().add(name);
            }
            int index = 1;
            for (Listitem item : fields.getItems()) {
                TableField field = item.getValue();
                Listcell c = (Listcell) item.getLastChild();
                if (field.getName() != null
                        && entity.getKey().contains(field.getName())) {
                    c.setIconSclass("z-icon-key");
                    c.setLabel("" + index++);
                    Listcell noNullCell = (Listcell) item.getChildren().get(5);
                    Checkbox noNullSwitchbox = (Checkbox) noNullCell.getChildren().get(0);
                    field.setNotNull(true);
                    noNullSwitchbox.setChecked(true);
                } else {
                    c.setIconSclass(null);
                    c.setLabel(null);
                }
            }
        } else {
            entity.setKey(new ArrayList<String>());
            entity.getKey().add(name);
            cell.setIconSclass("z-icon-key");
            cell.setLabel("1");
        }
        entity.setAutoKey(false);
        autokey.setChecked(false);
        setDirty();
    }

    private class foreignKeyObject implements EventListener<Event> {

        private Textbox name;

        private Chosenbox sourceFields;

        private Bandbox table;

        private Chosenbox toFields;

        private Textbox action;

        /**
         * @param name
         * @param sourceFields
         * @param table
         */
        public foreignKeyObject(Textbox name, Chosenbox sourceFields,
                                Bandbox table, Chosenbox toFields, Textbox action, A btn) {
            this.name = name;
            this.sourceFields = sourceFields;
            this.table = table;
            this.toFields = toFields;
            this.action = action;
            btn.addEventListener(Events.ON_CLICK, this);
            this.name.addEventListener(Events.ON_CHANGE, this);
            this.action.addEventListener(Events.ON_CHANGE, this);
            this.sourceFields.addEventListener(Events.ON_SELECT, this);
            this.toFields.addEventListener(Events.ON_SELECT, this);
            this.table.addEventListener(Events.ON_CHANGE, this);
            this.table.addEventListener(Events.ON_OPEN, this);
        }

        @Override
        public void onEvent(Event event) throws Exception {
            Row row = (Row) name.getParent();
            TableFk fk = row.getValue();
            if (Events.ON_OPEN.equals(event.getName())) {
                AbstractView.createEntityView(
                        new BandboxCallback(table,
                                Labels.getLabel("entity.table.fk.table")),
                        EntityType.TABLE.getName(), event.getTarget()).doOverlapped();
            } else if (Events.ON_OK.equals(event.getName())) {
                entity.getForeignKeys().remove(fk);
                row.detach();
                setDirty();
            } else if (event.getName().equals(Events.ON_CLICK)) {
                WebUtils.showConfirm(Labels.getLabel("button.delete"), this);
            } else {
                if (event.getTarget() == name)
                    fk.setName(name.getValue());
                else if (event.getTarget() == sourceFields) {
                    if (sourceFields.getSelectedObjects() != null)
                        fk.setSourceFields(Lang.concat(",",
                                sourceFields.getSelectedObjects()).toString());
                } else if (event.getTarget() == toFields) {
                    if (toFields.getSelectedObjects() != null)
                        fk.setToFields(Lang.concat(",",
                                toFields.getSelectedObjects()).toString());
                } else if (event.getTarget() == table) {
                    fk.setReferences(table.getValue());
                    if (!Strings.isBlank(fk.getReferences())) {
                        TableBean e = (TableBean) StudioApp.execute(null,
                                new GetEntityCmd(fk.getReferences()));
                        if (e != null) {
                            ListModelList<String> model = new ListModelList<String>(
                                    e.getFields().size());
                            for (TableField field : e.getFields())
                                model.add(field.getName());
                            toFields.setModel(model);
                            if (!Strings.isBlank(fk.getToFields())) {
                                try {
                                    toFields.setSelectedObjects(Arrays
                                            .asList(fk.getToFields().split(",")));
                                } catch (UiException ex) {
                                    toFields.setSelectedIndex(-1);
                                }
                            }
                        }
                    }
                } else if (event.getTarget() == action)
                    fk.setAction(action.getValue());
                setDirty();
            }
        }

    }

    private class IndexObject implements EventListener<Event> {

        private Textbox name;

        private Chosenbox fields;

        private Checkbox unique;

        /**
         * @param name
         * @param fields
         * @param unique
         */
        public IndexObject(Textbox name, Chosenbox fields, Checkbox unique,
                           A btn) {
            this.name = name;
            this.fields = fields;
            this.unique = unique;
            btn.addEventListener(Events.ON_CLICK, this);
            this.name.addEventListener(Events.ON_CHANGE, this);
            this.fields.addEventListener(Events.ON_SELECT, this);
            this.unique.addEventListener(Events.ON_CHECK, this);
        }

        @Override
        public void onEvent(Event event) throws Exception {
            Row row = (Row) name.getParent();
            TableIndex index = row.getValue();
            if (Events.ON_OK.equals(event.getName())) {
                entity.getIndexes().remove(index);
                row.detach();
                setDirty();
            } else if (event.getName().equals(Events.ON_CLICK)) {
                WebUtils.showConfirm(Labels.getLabel("button.delete"), this);
            } else {
                if (event.getTarget() == name)
                    index.setName(name.getValue());
                else if (event.getTarget() == fields) {
                    List<String> model = new ArrayList<String>(fields
                            .getSelectedObjects().size());
                    for (Object field : fields.getSelectedObjects())
                        model.add((String) field);
                    index.setFields(Lang.concat(",", model).toString());
                } else if (event.getTarget() == unique)
                    index.setUnique(unique.isChecked());
                setDirty();
            }
        }

    }

    private class FieldObject implements EventListener<Event> {

        private Textbox name;

        private Combobox type;

        private Intbox length;

        private Intbox decimal;

        private Textbox value;

        private Textbox desp;

        private Checkbox notnull;

        private Listcell key;

        private Textbox acc;

        private Combobox optionType;

        private Bandbox valueBandbox;

        public FieldObject(Textbox name, Combobox type, Intbox length,
                           Intbox decimal, Textbox value, Textbox desp, Checkbox notnull,
                           Listcell key, Textbox acc, Combobox optionType, Bandbox valueBandbox) {
            this.name = name;
            this.type = type;
            this.length = length;
            this.decimal = decimal;
            this.value = value;
            this.desp = desp;
            this.notnull = notnull;
            this.key = key;
            this.acc = acc;
            this.optionType = optionType;
            this.valueBandbox = valueBandbox;
            this.name.addEventListener(Events.ON_CHANGE, this);
            this.type.addEventListener(Events.ON_CHANGE, this);
            this.length.addEventListener(Events.ON_CHANGE, this);
            this.decimal.addEventListener(Events.ON_CHANGE, this);
            this.value.addEventListener(Events.ON_CHANGE, this);
            this.desp.addEventListener(Events.ON_CHANGE, this);
            this.notnull.addEventListener(Events.ON_CHECK, this);
            this.key.addEventListener(Events.ON_CLICK, this);
            this.acc.addEventListener(Events.ON_CHANGE, this);
            this.optionType.addEventListener(Events.ON_CHANGE, this);
            this.valueBandbox.addEventListener(Events.ON_CHANGE, this);
            this.valueBandbox.addEventListener(Events.ON_OK, this);
            this.valueBandbox.addEventListener(Events.ON_OPEN, this);
        }

        @Override
        public void onEvent(Event event) throws Exception {
            Listitem row = (Listitem) name.getParent().getParent();
            TableField field = row.getValue();
            if (Events.ON_CHANGE.equals(event.getName())
                    || Events.ON_CHECK.equals(event.getName())) {
                Component c = event.getTarget();
                if (c == name) {
                    String id = name.getValue().trim();
                    // 如果栏位在主键里面，更改名称
                    if (entity.getKey() != null) {
                        Iterator<String> itr = entity.getKey().iterator();
                        while (itr.hasNext()) {
                            if (itr.next().equalsIgnoreCase(field.getName())) {
                                itr.remove();
                                entity.getKey().add(id);
                                break;
                            }
                        }
                    }
                    // 如果栏位在索引里面，更改索引栏位
                    if (entity.getIndexes() != null) {
                        StringBuilder sb = new StringBuilder();
                        for (TableIndex idx : entity.getIndexes()) {
                            if (idx.getFields() != null) {
                                sb.setLength(0);
                                String[] fields = idx.getFields().split(",");
                                for (int i = 0; i < fields.length; i++) {
                                    if (fields[i].equals(field.getName()))
                                        sb.append(id);
                                    else
                                        sb.append(fields[i]);
                                    if (i < fields.length - 1)
                                        sb.append(",");
                                }
                                idx.setFields(sb.toString());
                            }
                        }
                        sb = null;
                    }
                    // 如果外键
                    if (entity.getForeignKeys() != null) {
                        StringBuilder sb = new StringBuilder();
                        for (TableFk fk : entity.getForeignKeys()) {
                            if (fk.getSourceFields() != null) {
                                sb.setLength(0);
                                String[] fields = fk.getSourceFields().split(
                                        ",");
                                for (int i = 0; i < fields.length; i++) {
                                    if (fields[i].equals(field.getName()))
                                        sb.append(id);
                                    else
                                        sb.append(fields[i]);
                                    if (i < fields.length - 1)
                                        sb.append(",");
                                }
                                fk.setSourceFields(sb.toString());
                            }
                        }
                    }
                    field.setName(id);
                } else if (c == type)
                    field.setType(FieldType.getType(type.getSelectedItem()
                            .getLabel()));
                else if (c == length)
                    field.setLength(length.getValue());
                else if (c == decimal)
                    field.setDecimal(decimal.getValue());
                else if (c == value)
                    field.setDefaultValue(value.getValue());
                else if (c == desp)
                    field.setDescription(desp.getValue());
                else if (c == notnull)
                    field.setNotNull(notnull.isChecked());
                else if (c == acc)
                    field.setAcc(acc.getValue());
                else if (c == optionType) {
                    Integer index = Integer.valueOf((String) optionType.getSelectedItem().getValue());
                    if (index == 2)
                        index = 1;
                    field.setOptionType(index);
                }
                setDirty();
            } else if (Events.ON_CLICK.equals(event.getName())) {// 选择主键
                if (Strings.isBlank(field.getName()))
                    WebUtils.showError(Labels.getLabel("entity.table.field.name.not.empty"));
                else
                    setPrimaryKey(field.getName(), (Listcell) event.getTarget());
            } else if (event instanceof OpenEvent || event.getName().equals(Events.ON_OK)) {
                final String val;
                if (event instanceof OpenEvent) {
                    OpenEvent evt = (OpenEvent) event;
                    val = (String) evt.getValue();
                } else {
                    val = valueBandbox.getValue();
                }

                if (optionType.getSelectedItem() != null) {
                    int index = optionType.getSelectedIndex();
                    final TableField field1 = field;
                    if (index == 1) {
                        AbstractView.createDicCodeView(valueBandbox, new EditorCallback<String>() {
                            @Override
                            public String getValue() {
                                return null;
                            }

                            @Override
                            public void setValue(String value) {
                                valueBandbox.setValue(value);
                                field1.setOptionValue(value);
                                setDirty();
                            }

                            @Override
                            public String getTitle() {
                                return Labels.getLabel("entity.table.dictionary");
                            }

                            @Override
                            public Page getPage() {
                                return valueBandbox.getPage();
                            }

                            @Override
                            public Editor getEditor() {
                                return null;
                            }
                        }).doOverlapped();
                    } else if (index == 0) {
                        WebUtils.showInfo(Labels.getLabel("entity.table.selectedType"));
                    } else if (index == 2) {
                        AbstractView.createTableCodeLabelView(valueBandbox, new EditorCallback<TableCodeLabelVo>() {
                            @Override
                            public TableCodeLabelVo getValue() {
                                TableCodeLabelVo tableCodeLabelVo = new TableCodeLabelVo();
                                if (Strings.isBlank(field1.getOptionValue()) == false) {
                                    String[] fieldList = field1.getOptionValue().split(",");
                                    if (fieldList.length == 3) {
                                        tableCodeLabelVo.setTableName(fieldList[0]);
                                        tableCodeLabelVo.setCodeName(fieldList[1]);
                                        tableCodeLabelVo.setLabelName(fieldList[2]);
                                    }
                                }
                                return tableCodeLabelVo;
                            }

                            @Override
                            public void setValue(TableCodeLabelVo value) {
                                String optionValue = null;
                                        List<String> list = new ArrayList<>();
                                if (Strings.isBlank(value.getTableName()) == false &&
                                        Strings.isBlank(value.getCodeName()) == false &&
                                        Strings.isBlank(value.getLabelName()) == false) {
                                    list.add(value.getTableName());
                                    list.add(value.getCodeName());
                                    list.add(value.getLabelName());
                                    optionValue = StringUtil.listToString(list, ",");
                                }
                                field1.setOptionValue(optionValue);
                                valueBandbox.setValue(optionValue);
                                setDirty();
                            }

                            @Override
                            public String getTitle() {
                                return Labels.getLabel("entity.table.table");
                            }

                            @Override
                            public Page getPage() {
                                return valueBandbox.getPage();
                            }

                            @Override
                            public Editor getEditor() {
                                return null;
                            }
                        }).doOverlapped();
                    }
                } else {
                    WebUtils.showInfo(Labels.getLabel("entity.table.selectedType"));
                }
            }
        }

    }
}
